from PyMybatis import  MapperParse

import pymysql.cursors

# 默认配置
options = {
    'host': '127.0.0.1',
    'port': 3306,
    'charset': 'utf8mb4',
    'cursorclass': pymysql.cursors.DictCursor,
    'log': False,
}


class PyMybatisError(TypeError):
    pass


def build(config):
    """"
    _:type config: dict 配置项，必备用户名/连接的数据库
    """
    if 'user' not in config or 'db' not in config or 'mapper' not in config:
        raise PyMybatisError("请配置user/db/mapper")
    options.update(config)
    temp = SqlSession().__createSession__(options)
    return temp


class SqlSession(object):
    """数据库会话，应创建为单例;；
    """
    __instance = None  # 单例对象
    __connection = None  # 连接
    __sql_dict = {}  # mapper存储容器
    __sql_template = {}  # 模板存储容器
    __log_sql = False

    def __new__(cls, *args, **kwargs):
        """使用__new__实现单例"""
        if not cls.__instance:
            cls.__instance = super(SqlSession, cls).__new__(cls)
        return cls.__instance

    def __createSession__(self, config):
        """调用创建连接方法,不建议主动调用此方法"""
        if not self.__connection:
            self.__init_sql_dom_tree(config['mapper'])
            # 初始化连接
            del config['mapper']
            self.__log_sql = config['log']
            del config['log']
            self.__connection = pymysql.connect(**config)
            if 'autocommit' not in config or config['autocommit'] is True:
                self.__connection.autocommit(True)
        return self

    def __init_sql_dom_tree(self, mapper_list, encoding='utf8'):
        """构建mapper容器"""
        if not self.__sql_dict:
            self.__sql_dict = MapperParse.init_sql_dom_tree(mapper_list, encoding)
        return self.__sql_dict

    def execute(self, sql):
        """执行自定义sql
        :return: 数组 0： 受影响行 1： 执行的游标(已关闭)
        """
        with self.__connection.cursor() as cursor:
            if self.__log_sql:
                print(sql)
            effect_row = cursor.execute(sql)
            return [effect_row, cursor]

    def update(self, namespace, sql_id, params={}):
        """通过sqlid调用SQL，可执行insert/update/delete
        :param sql_id:SQL
        :param namespace:mapper的命名空间
        _:return 返回受影响的行数
        """
        sql_ele = self.__sql_dict[namespace][sql_id]
        # sql = self.__batisSQL(sql_ele)
        # new_sql = MapperParse.replace(sql, params)
        new_sql = MapperParse.createSQL(sql_ele, params)
        return self.execute(new_sql)[0]

    def query(self, namespace, sql_id, params={} , get_one=False):
        """执行查询操作，可执行select
        :param get_one: bool 是否仅获取一条数据，默认False
        :param sql_id: str sql_id
        :param namespace: str mapper的命名空间
        :type params: dict 传入参数
        :return 返回数据 字典 元组
        """
        sql_ele = self.__sql_dict[namespace][sql_id]
        new_sql = MapperParse.createSQL(sql_ele, params)
        cursor = self.execute(new_sql)[1]
        if get_one:
            return cursor.fetchone()
        else:
            return cursor.fetchall()

    def insert(self, namespace, sql_id, params={}):
        """"
        _:return 返回自增id，若未定义自增id仅返回0
        """
        sql_ele = self.__sql_dict[namespace][sql_id]
        new_sql = MapperParse.createSQL(sql_ele, params)
        self.execute(new_sql)
        return self.__connection.insert_id()

    def commit(self):
        """commit操作，默认为自动提交,请在初始化时配置或用autocommit修改"""
        self.__connection.commit()
        return True

    def rollBack(self):
        """回滚到上次commit,仅在非自动提交有效"""
        self.__connection.rollback()
        return True

    def autocommit(self, mode):
        """修改是否自动提交"""
        self.__connection.autocommit(mode)

    def __del__(self):
        """当对象销毁时，关闭连接"""
        print("连接已关闭")
        if self.__connection:
            self.__connection.close()
